#pragma once
#include <string>
#include <vector>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <time.h>
#include <sys/wait.h>

// 父写子读 --- 根据读写内容完成相关的task

// 通道（描述）
class Channel
{
public:
    Channel(int wfd, pid_t pid) : _wfd(wfd), _pid(pid)
    {
        _name += "Channel:" + std::to_string(wfd) + "---" + std::to_string(pid);
    }
    std::string &GetName()
    {
        return _name;
    }
    int GetWfd()
    {
        return _wfd;
    }
    pid_t GetPid()
    {
        return _pid;
    }
    void Close()
    {
        close(_wfd);
    }
    void Wait()
    {
        waitpid(_pid, nullptr,0);
    }
    ~Channel()
    {
    }

private:
    int _wfd;   // 父写端
    pid_t _pid; // 自进程pid
    std::string _name;
};

//  通道管理（组织）
class ChannelManagement
{
public:
    ChannelManagement()
    {
    }
    void Insert(int wfd, pid_t pid)
    {
        _cl.emplace_back(wfd, pid);
    }
    void Print()
    {
        for (auto &v : _cl)
        {
            std::cout << v.GetName() << std::endl;
        }
    }
    int Choose()
    {
        int ret = _cl[_next].GetWfd();
        std::cout << "choose的子进程pid:" << _cl[_next].GetPid() << std::endl;
        (++_next) %= _cl.size();
        return ret;
    }
    void StopSubProcess()
    {
        for (auto &channel : _cl)
        {
            channel.Close();
            std::cout << "关闭: " << channel.GetName() << std::endl;
        }
    }
    void WaitSubProcess()
    {
        for (auto &channel : _cl)
        {
            channel.Wait();
            std::cout << "回收: " << channel.GetName() << std::endl;
        }
    }
    void StopAddWaitSubProcess()
    {
        for (auto &channel : _cl)
        {
            channel.Close();
            std::cout << "关闭: " << channel.GetName() << std::endl;
            channel.Wait();
            std::cout << "回收: " << channel.GetName() << std::endl;
        }
    }
    void Close()
    {
        //执行子进程关闭所有继承而来的哥哥的写端
        for (auto &channel : _cl)
        {
            channel.Close();
        }
    }
    ~ChannelManagement()
    {
    }

private:
    std::vector<Channel> _cl;
    int _next = 0;
};

const int poolnum = 5;

// pool主体
class ProcessPool
{
public:
    ProcessPool()
    {
        // 模拟task
        srand(time(nullptr));
        _ts.Register(PrintLog);
        _ts.Register(Download);
        _ts.Register(Upload);
    }
    void Work(int rfd)
    {
        while (true)
        {
            int n = 0;
            ssize_t ret = read(rfd, &n, sizeof(n));
            if (ret > 0)
            {
                if (ret != sizeof(n))
                    continue;
                else // task
                {
                    std::cout << "开始执行task,我的pid:" << getpid() << std::endl;
                    _ts.Execute(n);
                    std::cout << "task完成" << std::endl;
                    std::cout << "*******************************" << std::endl
                              << std::endl;
                }
            }
            else if (ret == 0) // 写端关闭
            {
                break;
            }
            else // error
            {
                break;
            }
        }
    }
    bool Start(int num)
    {
        for (int i = 0; i < num; i++)
        {
            // 1. 创建管道
            int fd[2] = {0};
            int ret = pipe(fd);
            if (ret < 0)
                return false;
            // 2. 创建子进程
            pid_t id = fork();
            if (id < 0)
                return false;
            else if (id == 0)
            {
                // 子关闭从父进程继承而来的其他哥哥进程的w端
                _cm.Close();
                // 子关闭写端
                close(fd[1]);
                Work(fd[0]);

                close(fd[0]);
                exit(0);
            }
            // 父 关闭读端
            close(fd[0]);
            // 描述+组织
            _cm.Insert(fd[1], id);
        }
        return true;
    }
    void Debug()
    {
        _cm.Print();
    }
    void Run()
    {
        // 1. 挑进程 -- 采用轮询的方式
        int wfd = _cm.Choose();
        // 2. 发任务
        PushTask(wfd);
    }
    void PushTask(int wfd)
    {
        int taskcode = rand() % _ts.Size();
        std::cout << "发的taskcode:" << taskcode << std::endl;
        int ret = write(wfd, &taskcode, sizeof(taskcode));
        if (ret < 0)
            return;
    }
    void Stop()
    {
        // _cm.StopSubProcess();
        // _cm.WaitSubProcess();
        _cm.StopAddWaitSubProcess();
    }
    ~ProcessPool()
    {
    }

private:
    ChannelManagement _cm; // 管理
    TaskMseeage _ts;
};